<template>
  <div class="side-tree-warp">
    <div class="resizeR"></div>
    <div class="side-tree" id="sideTree">
      <div class="search-box">
        <a-input v-model:value="searchFolder" placeholder="输入关键词" @keyup.enter="onSearchFolder" allow-clear @change="change">
          <template #prefix>
            <SearchOutlined style="color:#909399"  @click="onSearchFolder"/>
          </template>
        </a-input>
      </div>

      <div class="classify-box">
        <span class="classify-title tag-title" @click="clickAll">
          <span>智能标签</span>
          <img class="tree-down-all" src="@/assets/img/meadiaIndex/tree-down-all.png" alt="" />
        </span>
      </div>
      <div style="height: 190px; padding-bottom: 20px;">
      <a-tree v-if="gData.length" v-bind="$attrs" @select="selectTree" class="side-tree-draggable-tree side-tree-draggable-tree-tag" :load-data="onLoadData"
        :tree-data="gDataTag" v-model:expandedKeys="expandedKeys" v-model:selectedKeys="selectedKeys" :draggable="false" block-node
        @drop="onDrop" :fieldNames="{
          title: 'name',
          key: 'id',
        }"
        >
        <template #title="item">
          <img class="tree-folder-icon"  src="@/assets/img/meadiaIndex/tree-tag.png" alt="">
          <span class="tree-title" :title="item.name" :id="'nodeId_'+item.id+'_pid_'+item.parent_id" >{{ item.name }} </span>
          <span class="tree-count">4</span>
        </template>
      </a-tree>
    </div>


      <div class="classify-box">
        <span class="classify-title" @click="clickAll">
          <span>文件夹（7）</span>
          <img class="tree-down-all" src="@/assets/img/meadiaIndex/tree-down-all.png" alt="" />
        </span>
        <img class="new-icon" v-if="!isSearch"  @click="handAddFn()" src="@/assets/img/meadiaIndex/tree-add-icon.png" alt="" />
        <img class="tree-fun" src="@/assets/img/meadiaIndex/tree-fun-icon.png" alt="" />
      </div>
      <div style="height: calc(100vh - 402px); overflow-y: scroll;padding-bottom: 20px;">
      <a-tree v-if="gData.length" v-bind="$attrs" @select="selectTree" class="side-tree-draggable-tree" :load-data="onLoadData"
        :tree-data="gData" v-model:expandedKeys="expandedKeys" v-model:selectedKeys="selectedKeys" :draggable="false" block-node
        @drop="onDrop" :fieldNames="{
          title: 'name',
          key: 'id',
        }"
        >
        <template #title="item">
          <!-- v-if="item.parent_id=='0'" -->
          <img class="tree-folder-icon"  src="@/assets/img/meadiaIndex/tree-folder.png" alt="">
          <span class="tree-title" :title="item.name" :id="'nodeId_'+item.id+'_pid_'+item.parent_id" >{{ item.name }} </span>
          <span class="tree-count">4</span>
          <span class="handleBox-tree" @click.stop v-if="!isSearch">
            <img class="tree-add" @click="handAddFn(item)" src="@/assets/img/meadiaIndex/tree-add-icon.png" alt="" />
            <span class="handleBox-fn">
              <a-popover placement="bottom" overlayClassName="tree-oper-pop">
                <template #content>
                  <div class="tree-handleBox">
                    <p @click="handNameFn(item)">
                      <img class="small-icon" src="@/assets/img/meadiaIndex/tree-rename-icon.png" alt="">
                      <span>重命名</span>
                    </p>
                    <p @click="handDeleteFnConfirm(item)">
                      <img class="small-icon" src="@/assets/img/meadiaIndex/tree-delete-icon.png" alt="">
                      <span>删除</span>
                    </p>
                  </div>
                </template>
                <img class="tree-fun" src="@/assets/img/meadiaIndex/tree-fun-icon.png" alt="" />
              </a-popover>

              <!-- -->
            </span>
          </span>
        </template>
      </a-tree>
    </div>

      <div v-if="!gData.length && !loading" class="no-data-box">
        <img
            src="@/assets/img/meadiaIndex/noData-icon.png"
            class="no-data-icon"
          />
          <span class="no-more-data"> 暂无数据 </span>
      </div>
    </div>
  </div>

  <!-- 新增栏目  -->
  <a-modal v-model:open="dialogAddVisible" title="新增文件夹" @ok="submitAddModel">
    <div class="wrapper-new">
      <label>文件夹名称：</label>
      <a-input v-model:value="selectItemName" placeholder="请输入文件夹名称" style="padding: 6px;" />
    </div>
  </a-modal>
</template>
<script setup lang="ts">
import { ref, onMounted, nextTick } from 'vue';
import type {
  AntTreeNodeDragEnterEvent,
  AntTreeNodeDropEvent,
  TreeProps,
} from 'ant-design-vue/es/tree';
import {
  SearchOutlined
} from "@ant-design/icons-vue";
import { message, Modal } from "ant-design-vue";
import request from "@/service/axios";
import { useFileInfoStore } from "@/store/fileInfo";

const useFileInfo = useFileInfoStore();
const emit = defineEmits(['setShowTree','searchAllData','selectTree', 'SuccessfuCallbackFn', 'handNameFn','createFolder','handleTreeDelete','handleTreeMove']);

const loading = ref(false)
const searchFolder = ref('')
let isSearch = ref(false)
// 新增媒资分类树结构一些变量
const dialogAddVisible = ref<boolean>(false);
const selectItemObj = ref<any>({});
const selectItemName = ref<string>('');
const expandedKeys = ref<string[]>();
// tree一级下是否有更多
const rootTreeNoMore = ref<boolean>(false);

const selectedKeys: any = ref<string[]>();
const gData = ref<any>([]);
const gDataTag = ref<any>([
    {
        id: "0",
        id_path: "/0",
        if_has_childs: false,
        name: "全部",
        parent_id: "0",
        path: "/root/刘阳测试文件夹"
    },
    {
        id: "65b0d0492ccf7a2e3fbb17d0",
        id_path: "/0/65b0d0492ccf7a2e3fbb17d0",
        if_has_childs: false,
        name: "未分类",
        parent_id: "0",
        path: "/root/刘阳测试文件夹"
    },
    {
        id: "3",
        id_path: "/0/3",
        if_has_childs: false,
        name: "全部标签",
        parent_id: "0",
        path: "/root/刘阳测试文件夹"
    },
    {
        id: "4",
        id_path: "/0/4",
        if_has_childs: false,
        name: "人物信息",
        parent_id: "0",
        path: "/root/刘阳测试文件夹"
    },
    {
        id: "65b0d0492ccf7a2e3fbb17d0",
        id_path: "/0/65b0d0492ccf7a2e3fbb17d0",
        if_has_childs: false,
        name: "回收站",
        parent_id: "0",
        path: "/root/刘阳测试文件夹"
    }
]);
// 可视区域监测
const observer = new IntersectionObserver((entries)=>{
    entries.forEach((item) => {
      
      if (item.isIntersecting) {
        // 进入可视区域
          const id = item.target.id.split("_")[1]
          const pid = item.target.id.split("_")[3]
          // 针对展开的tree节点出现再可视区域进行滚动加载更多
          if(expandedKeys.value?.includes(pid)){
            const oneNode = document.querySelector('#nodeId_'+id+'_pid_'+pid) as HTMLElement;
            observer.unobserve(oneNode);
            getTreeData({id,pid},true)
          }
      }
    })
});
// 设置被选中的数据
const setSelectedKeys = (sk: any) => {
  selectedKeys.value = sk
}

const onDrop = (info: AntTreeNodeDropEvent) => {
  // 放大哪个节点id的下面
  const dropKey = info.node.key;
  // 拖拽的节点的id
  // const dragKey = info.dragNode.key;
  // 同级目录下移动无效（相当于没移动，本期功能没说需要排序）
  if (info.dragNode.parent_id == dropKey) {
    return
  }
  sureMoveFn(info.dragNode, info.node)

};
// 移动文件调接口
const sureMoveFn = async (dragNode: any, dropNode: any) => {
    const file_id =  dragNode.key
    const dataList = await getTreeData({id:dropNode.key})
    expandedKeys.value.push(dropNode.key)

    let if_merge =false
    const value = dataList.find(e => e.name == dragNode.name);
    if (value) {
        if (!confirm('确定合并相同新文件夹')) { return; }
        if_merge = true;
    }
    request({
      url: "/mediaresource-manage-service/resource/path",
      method: "put",
      data: {
        "location": 2,
        "target_id": dropNode.key,
        "if_merge": if_merge,
        "file_id": dragNode.key
      },
    }).then(async () => {
      // 递归删除移除的节点
      // deleteOneNode(gData.value, dragNode.key)
      // // 调接口更新拖拽后的节点 (这种方式有问题，箭头会出现消失的问题)
      // getTreeData(dropNode).then(async () => {
      //     // 移动后，这里需要调接口更新右侧面包屑和内容
      //     emit("handleTreeMove", {id:file_id})
      // })
      await refreshTreeMoveData({file_id,target_id: dropNode.key})
      // 脱宅的节点的父级节点判断
      nodeIsLeafBefore({parent_id:dragNode.parent_id})
      // 目标节点的判断
      nodeIsLeafBefore({parent_id:dropNode.key})
      // 移动后，这里需要调接口更新右侧面包屑和内容
      emit("handleTreeMove", {id:file_id})
    })
};
// 递归删除移除的节点
const deleteOneNode = (chilren: any, id: any) => {
  const _i = chilren.findIndex(v => {
    return v.id == id
  })
  if (_i != -1) {
    chilren.splice(_i, 1)
    return true
  } else {
    chilren.forEach((v: any) => {
      if (v.children) {
        deleteOneNode(v.children, id)
      }
    })
  }
}
const resetTreeData = ()=>{
  expandedKeys.value = []
  rootTreeNoMore.value = false
  onSearchFolder()
}
// 右侧删除后，更新左侧树
const refreshDeleteData = (item:any) => {
  deleteOneNode(gData.value,item.id)
  // nodeIsLeafBefore(item)
  const parent_id = getParentIdByIdPath(item)
  getTreeData({id:getParentIdByIdPath(item)}).then((dataList:any)=>{
      const clist=  dataList
      hanldeTreeMoveAddData( gData.value,parent_id,clist)
      gData.value = [...gData.value];
      // nodeIsLeafBefore({parent_id:parent_id})
  })
  
}
// 右侧重命名后，递归更新对应的文件夹名称
const refreshTreeName = (item: any,chilren?: any, ) => {
  if(!chilren){
    chilren =  gData.value
  }
  const _o = chilren.find(v => {
    return v.id == item.id
  })
  if(_o){
    _o.name = item.name
    return
  }else{
    chilren.forEach((v: any) => {
      if (v.children) {
        refreshTreeName( item,v.children)
      }
    })
  }
}

// 右侧新增文件夹后，递归更新对应的目录
const refreshTreAdd = (item: any,chilren?: any, ) => {
  if(useFileInfo.directory_id == '0'){
    gData.value.unshift({
      id: item.id,
      name: item.name
    })
    return
  }
  if(!chilren){
    chilren =  gData.value
  }
  const _o = chilren.find(v => {
    return v.id == item.parent_id
  })
  if(_o){
    if(!_o.children) _o.children= []
    _o.children.unshift({
      id: item.id,
      name: item.name
    })
    return
  }else{
    chilren.forEach((v: any) => {
      if (v.children) {
        refreshTreAdd( item,v.children)
      }
    })
  }
}

// 新增
const handAddFn = (item?: any) => {
  if (item) {
    const directory_id = item.id ? item.id : '0';
    useFileInfo.setDirectoryId(directory_id.toString());
    selectItemObj.value = item;
  } else {
    const directory_id =  '0';
    useFileInfo.setDirectoryId(directory_id.toString());
    selectItemObj.value = {};
  }
  selectItemName.value = '';
  dialogAddVisible.value = true
}

// 调接口新增文件
const submitAddModel = () => {
  if (selectItemName.value == "") {
    message.info("请输入名称");
    return;
  }
  request({
    url: "/mediaresource-manage-service/medias/folders",
    method: "post",
    data: {
      id: selectItemObj.value.id || "0",
      name: selectItemName.value
    }
  }).then(res => {
    dialogAddVisible.value = false
    if (res.data.status_code === 0) {
      message.error(res.data.msg);
      return;
    }
    message.success('文件夹创建成功');
    const newFileObj = {
      id: res.data.result.data,
      name: selectItemName.value,
      isLeaf:true
    }
    if (selectItemObj.value.id) {
      if (!selectItemObj.value.dataRef.children) {
        selectItemObj.value.dataRef.children = []
      }
      selectItemObj.value.dataRef.children.unshift(newFileObj)
    } else {
      gData.value.unshift(newFileObj)
    }
    nodeIsLeafBefore({parent_id:selectItemObj.value.id || "0"})
    // 刷新右侧树结构
    emit("createFolder", 'folder-success')
  }).finally(() => {
    dialogAddVisible.value = false
  })
}
// 重命名
const handNameFn = (item: any) => {
  item.media_resource_id = item.id
  item.title = item.name
  emit("handNameFn", item)
}

// 添加确认弹框
const handDeleteFnConfirm = (item: any) => {
  Modal.confirm({
    content: '确定删除媒资?',
    okText: '确认',
    cancelText: '取消',
    onOk() {
      handDeleteFn(item);
    },
    onCancel() {
      console.log('Cancel');
    }
  });
}

// list 操作- 删除
const handDeleteFn = (item: any) => {
  // if (!confirm("确定删除媒资?")) { return }
  let postObj: any = {
    is_media: 1,
    location: 1,
    files: [item.id]
  };
  request({
    url: "/mediaresource-manage-service/resource/file",
    method: "delete",
    data: postObj,
  }).then((res) => {
    message.success("删除成功");
    deleteOneNode(gData.value, item.id)
    nodeIsLeaf(gData.value, item.parent_id)
    // emit('SuccessfuCallbackFn')
    // 删除左侧，处理右侧是否需要联动更新
    emit('handleTreeDelete',item)
  });
};


// 点击树
const selectTree = (sk: any, e: any) => {
  if(e.selected) {
    emit("selectTree", sk, e)
  }else{
    // 防止重复点击同一个文件夹
    selectedKeys.value = [e.node.id]
  }
}

// 全部
const clickAll = () =>{
  selectedKeys.value = []

  // emit("selectTree", [], {selected:false,})
  emit("searchAllData")
}

// 懒加载获取树数据
const onLoadData = (treeNode: any) => {
  if(isSearch.value) return Promise.resolve([])
  return getTreeData(treeNode)
}
// 如果parent_id直接判断；否则有id_path,，从id_path取parent_id
const getParentIdByIdPath = (item)=>{
  if(item.parent_id || item.parent_id==='0'){
    return  item.parent_id
  }else if(item.id_path){
    // 如果只有id_path,没有parent_id时候，从id_path取parent_id
     const arr =  item.id_path.split(/\//).filter(v=> v);
     const _i = arr.findIndex(v=> v==item.id)
     if(_i>0) {
      item.parent_id = arr[_i-1]
        return  item.parent_id
     }
  }
}
// nodeIsLeaf的入口
const nodeIsLeafBefore = (item:any)=>{
    nodeIsLeaf(gData.value, getParentIdByIdPath(item))
}
// 判断某个节点是否是叶子节点，如果叶子节点:isLeaf要设置fale,否则是true。（主要用于新增，删除，移动后父级是否还有箭头）
const  nodeIsLeaf = (chilren: any, id: any)=>{
  const _i = chilren.findIndex(v => {
    return v.id == id
  })
  if (_i != -1) {
    // if(!chilren[_i].isLeaf){
    //   return 
    // }
    if(chilren[_i].children?.length){
      chilren[_i].isLeaf =  false
    }else{
      chilren[_i].isLeaf =  true
    }
    return true
  } else {
    chilren.forEach((v: any) => {
      if (v.children) {
        nodeIsLeaf(v.children, id)
      }
    })
  }
}
// 移动右侧，更新左侧  移动逻辑：先删除移除前的树，在调接口更新移到目标节点的数据
const refreshTreeMoveData =(item:any)=>{
  deleteOneNode(gData.value, item.file_id)
  // nodeIsLeafBefore(item)
  
  const target_id = item.target_id
  return new Promise((resolve)=>{
    getTreeData({id:target_id}).then((dataList:any)=>{
        const clist=  dataList
        hanldeTreeMoveAddData( gData.value,target_id,clist)
        gData.value = [...gData.value];
        // nodeIsLeafBefore({parent_id:target_id})
        resolve(null)
    })
  }) 
}
// 递归更新移到位置目标位置的数据
const hanldeTreeMoveAddData = (chilren: any, id: any,clist:any) => {
  const _o = chilren.find(v=>{
   return v.id == id
  })
  if(_o){
    _o.children = clist
    return 
  }else{
    chilren.forEach((v: any) => {
      if (v.children) {
        hanldeTreeMoveAddData(v.children, id,clist)
      }
    })
  }
}
// tree数据滚动加载更多
const treeSrollToLoadFn  = ()=>{
  const rollContainer = document.querySelector('#sideTree') as HTMLElement;
  rollContainer.addEventListener("scroll", () => {
      const clientHeight = rollContainer.clientHeight;
      const scrollTop = rollContainer.scrollTop;
      const scrollHeight = rollContainer.scrollHeight;
      if (scrollTop > 0 && Number(clientHeight) + Number(Math.floor(scrollTop)) >= Number(scrollHeight) - 5 && !loading.value) {
        // tree到底了
        getTreeData(null,true)
      }
  })
}
// 获取tree数据
const getTreeData = (treeNode: any,isLoadMore?:boolean) => {
  loading.value = true
  let folder_id = '0'
  let last_id = ''
  if(isLoadMore){
    
    if(treeNode?.pid){
        last_id = treeNode.id 
        folder_id = treeNode.pid
    }else if(gData.value.length && !rootTreeNoMore.value){
      last_id =  gData.value[gData.value.length-1].id
      folder_id = '0'
    }else{
      return
    }
  }else if (!treeNode) {
    gData.value = []
  }else {
    folder_id = treeNode.id || '0'
  }
  
  return new Promise<void>(resolve => {
    request({
      url: "/mediaresource-manage-service/resource/hierarchy/folder",
      method: "post",
      data: {
        files: [],
        folder_id: folder_id,
        location: 2,
        last_id
      }
    }).then((res) => {
      let dataList = res.data.result.data || []
      // 如果是叶子节点就不会显示哪个树箭头了
      dataList = dataList.map((v:any)=>{
        return {
          ...v,
          isLeaf:!v.if_has_childs
        }
      })
      // 如果是tree滚动加载更多
      if(isLoadMore){
        if(treeNode?.pid){
          // 非第一级滚动加载更多
          treeAppendChildData(gData.value,dataList,last_id)
          gData.value = [...gData.value];
          if(res.data.result.page){
            nextTick(()=>{
              if(dataList.length>=30){
                let noded = dataList[dataList.length-1]
                const oneNode = document.querySelector('#nodeId_'+noded.id+'_pid_'+ noded.parent_id) as HTMLElement;
                observer.observe(oneNode);
              }
            })
          }
        }else{
          // 第一级tree滚动加载更多
          const bol = gData.value.some((v)=>{
            return dataList.some((vv)=> vv.id ==v.id)
          })
          if(bol){
            // 一级下面没数据了
            rootTreeNoMore.value = true
            return
          }else{
            gData.value.push(...dataList)
          }
        }
      }else if (!treeNode) {
        // 第一次加载
        gData.value = dataList
      } else if(treeNode.dataRef){
        // 懒加载
        treeNode.dataRef.children = dataList;
        gData.value = [...gData.value];
        nextTick(()=>{
          if(dataList.length>=30){
            let noded = dataList[dataList.length-1]
            const oneNode = document.querySelector('#nodeId_'+noded.id+'_pid_'+ noded.parent_id) as HTMLElement;
            observer.observe(oneNode);
          }
        })
      }
      loading.value = false
      resolve(dataList)
    }).finally(()=>{
      loading.value = false
    })
  })
}
// 滚动加载子树的数据回到(哪个树展开着，滚动就记载到哪棵树下)
const  treeAppendChildData = (chilren:any,dataList:any,id:string)=>{
  const _i = chilren.findIndex((v:any) => {
    return v.id == id
  })
  if (_i != -1) {
    const bol = gData.value.some((v)=>{
      return dataList.some((vv)=> vv.id ==v.id)
    })
    if(bol){
      // 当前展开的子集下没更多数据了
      return false
    }else{
      chilren.push(...dataList)
    }
    return true
  } else {
    chilren.forEach((v: any) => {
      if (v.children) {
        treeAppendChildData(v.children,dataList, id)
      }
    })
  }
}
const setShowTree= ()=>{
  emit('setShowTree')
}
const change = (row:any) => {
  if (row.type == 'click' || !searchFolder.value ) {
    initData()
  }
}
// 搜索
const onSearchFolder = () => {
  expandedKeys.value  = []
  if(!searchFolder.value){
    initData()
    return 
  }
  isSearch.value= true
  loading.value = true
    request({
        url: "/multimodal-search-service/mediaresource/search",
        method: "post",
        data: {
            "query_text":  searchFolder.value,
            "query_type":0,
            "listType": 7,
            "mainType": 7,
            "ifTimeDesc":true,
            "lastId":0,
            "status":2,
            "folder_id": ""
        }
    }).then(res => {
      loading.value = false
      let list = []
      const resList =  res.data.result.data || []
      expandedKeys.value = []
      if(resList.length===0){
        gData.value =  []
        return
      }
      for (let i in resList) {
         let item =  resList[i]
        // && i<1
         if(item.id_path){
             const arrId = item.id_path.split(/\//).filter((v:any)=> v);
             const arrPath = item.path.split(/\//).filter((v:any)=> v);
             arrId.forEach((v:any,i:number)=>{
              if(i!=0){
                if(!expandedKeys.value.includes(v)){
                  expandedKeys.value.push(v)
                  list.push({
                    id:v,
                    name: arrPath[i],
                    parent_id: arrId[i-1],
                  })
                }
              }
             })
         }
      }
      // 如果搜索出来的数据量过大影响js性能的话，可以跟产品商量取多少条
      // list =  list.slice(0,100);
      const treeData = convertToTree(list);
      gData.value =  treeData
    }).finally(()=>{
      loading.value = false
    })
}
// 扁平化数组转tree状结构
function convertToTree(flatData:any, parent_id ='0') {
    const children = flatData.filter((node:any) => node.parent_id == parent_id);
    if (!children.length) {
        return null;
    }
    return children.map((node:any) =>{
      // expandedKeys.value.push(node.id)
      return {
          ...node,
          children: convertToTree(flatData, node.id)
      }
    });
}

// 改变树宽度大小函数
const resize = () => {
  const oparent: any = document.querySelector('.side-tree');
  const handle: any = document.querySelector('.resizeR');
  const dragMinWidth = 166;
  const dragMaxWidth = 500;
  let disX = 0;
  let disY = 0;
  handle.onmousedown = function (e) {
    e = e || event;
    e.preventDefault();
    disX = e.clientX - this.offsetLeft;
    disY = e.clientY - this.offsetTop;

    document.onmousemove = function (e) {
      e = e || event;
      let iL = e.clientX - disX;
      let iT = e.clientY - disY;
      let iw = handle.offsetWidth + iL;

      if (iw < dragMinWidth) {
        iw = dragMinWidth
      } else if (iw > dragMaxWidth) {
        iw = dragMaxWidth;
      };
      oparent.style.width = iw + 'px';
      return false;
    };
    document.onmouseup = function () {
      document.onmousemove = null;
      document.onmouseup = null;
    };
  };
};

const initData = () => {
  isSearch.value= false
  rootTreeNoMore.value = false
  getTreeData(null,false)
  resize()
}


onMounted(() => {
  initData()
  treeSrollToLoadFn()
})

defineExpose({
  setSelectedKeys,
  resetTreeData,
  refreshTreeName,
  refreshTreAdd,
  refreshDeleteData,
  refreshTreeMoveData,

});

</script>
<style lang="scss"  src="./SideTree.scss"></style>